<?php
namespace juven\controllers {
    \defined( '_JEXEC' ) or die( 'Restricted access' );
    
    class ctrl_login extends \juven\libs\Controller{
        const EVENT_onWarning_LoginRequestFromAccountWithUnknownState = "event_onWarning_LoginRequestFromAccountWithUnknownState";
        const EVENT_onWarning_UnknownHttpRequestMethod                = "event_onWarning_UnknownHttpRequestMethod";
        const EVENT_onWarning_BadLoginFormSubmited                    = "event_onWarning_BadLoginFormSubmited";
        const EVENT_onWarning_InternalError                           = "event_onWarning_InternalError";
        const EVENT_onWarning_GuestAccountLoginRequest                = "event_onWarning_GuestAccountLoginRequest";
        const EVENT_onNotice_InactiveAccountLoginRequest              = "event_onNotice_InactiveAccountLoginRequest";
        const EVENT_onNotice_BlockedAccountLoginRequest               = "event_onNotice_BlockedAccountLoginRequest";
        const EVENT_onNotice_UsernameDoesNotExistsInDatabase          = "event_onNotice_UsernameDoesNotExistsInDatabase";
        const EVENT_onNotice_WrongPassword                            = "event_onNotice_WrongPassword";
        const EVENT_onAdministratorLogin                              = "event_onAdministratorLogin";
        const EVENT_onWarning_UserLoginHasBeenCanceledBySomeEventHandler = "event_onWarning_UserLoginHasBeenCanceledBySomeEventHandler";
        
        const EVENT_onError                             = "event_onError";
        const EVENT_onBeforeLogin                       = "event_onBeforeLogin";
        const EVENT_onSuccesfulLogin                    = "event_onSuccesfulLogin";
        const EVENT_onFailedLogin                       = "event_onFailedLogin";
        
        protected function _init(){
            $this->model = $this->loadModel($this->_unPrefixedControllerName);
        }
        
        public function action_index(){
            if ($_SERVER['REQUEST_METHOD']==="POST"){ 
                $r = $this->proccessLoginData();
                switch ((integer)$r->error_code) {
                    case 100:
                        $this->view->error_msg = "Incorrect username and/or password";
                        $this->renderLoginPage();
                        break;
                    case 200:
                        $this->view->error_msg = "Incorrect username and/or password";
                        $this->renderLoginPage();
                        break;
                    case 201:
                        $this->view->error_msg = $r->error_msg;
                        $this->renderLoginPage();
                        break;
                    case 202:
                        $this->view->error_msg = $r->error_msg;
                        $this->renderLoginPage();
                        break;
                    case 300:
                        $this->view->error_msg = "Incorrect username and/or password";
                        $this->renderLoginPage();
                        break;
                    case 301:
                        $this->view->error_msg = $r->error_msg;
                        $this->renderLoginPage();
                        break;
                    case 302:
                        $this->view->error_msg = $r->error_msg;
                        $this->renderLoginPage();
                        break;
                    case 400:
                        $this->view->error_msg = "There was an undefined error(".$r->error_code."), please try again later.";
                        $this->renderLoginPage();
                        break;
                    case 401:
                        $this->view->error_msg = "Incorrect username and/or password";
                        $this->renderLoginPage();
                        break;
                    case 500:
                        $this->view->error_msg = "Incorrect username and/or password";
                        $this->renderLoginPage();
                        break;
                    case 1000:
                        $this->view->error_msg = "Your account has been suspended. please contact customer service";
                        $this->renderLoginPage();
                        break;
                    case 1001:
                        $this->view->error_msg = "Your account has been blocked. please contact customer service";
                        $this->renderLoginPage();
                        break;
                    case 1002:
                        $this->view->error_msg = "There was an undefined error(".$r->error_code."), please try again later.";
                        $this->renderLoginPage();
                        break;
                    case 2000:
                        $this->view->error_msg = "Incorrect username and/or password";
                        $this->renderLoginPage();
                        break;
                    case 3333:
                        $this->view->error_msg = "Your account has been blocked. please contact customer service";
                        $this->renderLoginPage();
                        break;
                    case 9999:
                        $this->view->error_msg = "Succesful login";
//                        $this->renderLoginPage();
                        \juven\libs\Tools::redirect("index");
                        break;
                    default:
                        $this->view->error_msg = "There was an undefined error(".$r->error_code."), please try again later.";
                        $this->renderLoginPage();
                        break;
                }
            }
            elseif ($_SERVER['REQUEST_METHOD']==="GET"){
                if (isset($this->view->error_msg)){ unset($this->view->error_msg); }
                $this->renderLoginPage();
            } else {
                $dtp = new \stdClass();
                $dtp->RequestMethod = $_SERVER['REQUEST_METHOD'];
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_UnknownHttpRequestMethod, $dtp);
                if (isset($this->view->error_msg)){ unset($this->view->error_msg); }
                $this->renderLoginPage();
            }
        }
        
        private function renderLoginPage(){
            $this->view->pageTitle = "Login";
            $this->view->render($this->_unPrefixedControllerName);
        }
        
        /**
         * 
         * @return object Returns an object (\stdClass). This object has 2 properties: error_msg and error_code. if error_code=0 then we have succesful login
         */
        private function proccessLoginData(){
            $dtp = new \stdClass();
            $dtp->error_msg = "undefined";
            $dtp->error_code = -1;
            
            $c = \count($_POST);
            if ($c!==3){
                $dtp->error_msg = "The number of fields in this form is different($c) than it should be";
                $dtp->error_code= 100;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_BadLoginFormSubmited, $dtp);
                return $dtp;
            }
            
            if (!isset($_POST["username"])){
                $dtp->error_msg = "[Username] field of Login form, is missing";
                $dtp->error_code= 200;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_BadLoginFormSubmited, $dtp);
                return $dtp;
            }
            
            $un_len = \strlen($_POST["username"]);
            if ($un_len<\juven\libs\juven::config()->Login->username_minLength || $un_len>\juven\libs\juven::config()->Login->username_maxLength){
                $dtp->error_msg = "[Username] field length($un_len) out of bounds(".(string)\juven\libs\juven::config()->Login->username_minLength.
                        " < length < ".(string)\juven\libs\juven::config()->Login->username_maxLength.")";
                $dtp->error_code= 201;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_BadLoginFormSubmited, $dtp);
                return $dtp;
            }
            
            for ($i = 0; $i < $un_len; $i++){
                if (!\in_array(\substr($_POST["username"], $i, 1), \juven\libs\juven::config()->Login->username_allowedChars)){ 
                    $dtp->error_msg = "[Username] field contains illegal characters";
                    $dtp->error_code= 202;
                    \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_BadLoginFormSubmited, $dtp);
                    return $dtp;
                }
            }
            
            if (!isset($_POST["password"])){
                $dtp->error_msg = "[Password] field is missing";
                $dtp->error_code= 300;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_BadLoginFormSubmited, $dtp);
                return $dtp;
            }
            
            $pw_len = \strlen($_POST["password"]);
            if ($pw_len<\juven\libs\juven::config()->Login->password_minLength || $pw_len>\juven\libs\juven::config()->Login->password_maxLength){
                $dtp->error_msg = "[Password] field length($pw_len) out of bounds(".(string)\juven\libs\juven::config()->Login->password_minLength.
                        " < length < ".(string)\juven\libs\juven::config()->Login->password_maxLength.")";
                $dtp->error_code= 301;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_BadLoginFormSubmited, $dtp);
                return $dtp;
            }
            
            for ($i = 0; $i < $pw_len; $i++){
                if (!\in_array(\substr($_POST["password"], $i, 1), \juven\libs\juven::config()->Login->password_allowedChars)){ 
                    $dtp->error_msg = "[Password] field contains illegal characters";
                    $dtp->error_code= 302;
                    \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_BadLoginFormSubmited, $dtp);
                    return $dtp;
                }
            }
            
            $re = $this->model->find_username($_POST["username"]);
            if (!\is_array($re)){
                $dtp->error_msg = "Could not get correct results from database";
                $dtp->error_code= 400;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_InternalError, $dtp);
                return $dtp;
            }
            
            if (\count($re)<1){
                $dtp->error_msg = "Username was not found";
                $dtp->error_code= 401;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onNotice_UsernameDoesNotExistsInDatabase, $dtp);
                return $dtp;
            }
            
            if ($re[0]["id"]==\juven\libs\juven::config()->db->guest_userID){
                $dtp->error_msg = "Guest account login request";
                $dtp->error_code= 500;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_GuestAccountLoginRequest, $dtp);
                return $dtp;
            }
            
            // now check if passwords match
            // todo: password encryption !!!!!
            if ($_POST["password"]===$re[0]["password"]){
                if ($re[0]["status"]==0){ // user is inactive !!!
                    $dtp->error_msg = "Account is inactive";
                    $dtp->error_code= 1000;
                    \juven\libs\juven::eventsManager()->publish(self::EVENT_onNotice_InactiveAccountLoginRequest, $dtp);
                    return $dtp;
                } elseif ($re[0]["status"]==1){ // user is active
                    //just continue execution...
                } elseif ($re[0]["status"]==2) { // user is blocked !!!
                    $dtp->error_msg = "Account is blocked";
                    $dtp->error_code= 1001;
                    \juven\libs\juven::eventsManager()->publish(self::EVENT_onNotice_BlockedAccountLoginRequest, $dtp);
                    return $dtp;
                } else { // user in an unknown state!!!
                    $dtp->error_msg = "Account has unknown state";
                    $dtp->error_code= 1002;
                    \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_LoginRequestFromAccountWithUnknownState, $dtp);
                    return $dtp;
                }
                
                $dtp1 = new \stdClass();
                $dtp1->id            = $re[0]["id"];
                $dtp1->username      = $re[0]["username"];
                $dtp1->email_address = $re[0]["email_address"];
                $dtp1->allow_it      = \TRUE;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onBeforeLogin, $dtp1);
                if ($dtp1->allow_it!==\TRUE){
                    $dtp->error_msg = "User (id:".$dtp1->id.") login has been canceled by some event handler";
                    $dtp->error_code= 3333;
                    \juven\libs\juven::eventsManager()->publish(self::EVENT_onWarning_UserLoginHasBeenCanceledBySomeEventHandler, $dtp);
                    return $dtp;
                }
                
                \juven\libs\juven::user()->login($re[0]);
                $dtp->error_msg = "Succesful login";
                $dtp->error_code= 9999;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onSuccesfulLogin, $dtp);
                return $dtp;
            } else {
                $dtp->error_msg = "Wrong Password";
                $dtp->error_code= 2000;
                \juven\libs\juven::eventsManager()->publish(self::EVENT_onNotice_WrongPassword, $dtp);
                return $dtp;
            }
        }
    }
}
?>
